package com.lzc.springcloud.user.domain.identity;

import com.lzc.springcloud.user.domain.BasicEntity;
import com.lzc.springcloud.user.domain.DomainRegistry;

import javax.persistence.*;
import java.util.Objects;
import java.util.Set;
import java.util.regex.Pattern;

@Entity
@Table(name = "sys_user", schema = "demo", catalog = "")
public class SysUserEntity extends BasicEntity {

    @Id
    @Column(name = "user_id", nullable = false)
    private long userId;
    @Basic
    @Column(name = "username", nullable = false, length = 50)
    private String username;
    @Basic
    @Column(name = "name", nullable = true, length = 50)
    private String name;
    @Basic
    @Column(name = "password", nullable = true, length = 100)
    private String password;
    @Basic
    @Column(name = "email", nullable = true, length = 100)
    private String email;
    @Basic
    @Column(name = "mobile", nullable = true, length = 100)
    private String mobile;
    @Basic
    @ManyToMany(targetEntity = SysRoleEntity.class, cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinTable(name = "sys_user_role",
            joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "user_id")},
            inverseJoinColumns = {@JoinColumn(name = "role_id", referencedColumnName = "role_id")}
    )
    private Set<SysRoleEntity> roleEntities;

    public SysUserEntity() {
        super();
    }

    public SysUserEntity(String username, String name, String password, String email, String mobile) {
        this.username = username;
        this.name = name;
        this.password = asEncryptedValue(password);
        this.email = email;
        this.mobile = mobile;
    }

    public long userId() {
        return userId;
    }

    protected void setUserId(long userId) {
        this.userId = userId;
    }

    public String username() {
        return username;
    }

    protected void setUsername(String username) {
        this.username = username;
    }

    public String name() {
        return name;
    }

    protected void setName(String name) {
        this.name = name;
    }

    public String password() {
        return password;
    }

    protected void setPassword(String password) {
        this.password = asEncryptedValue(password);
    }

    public String email() {
        return email;
    }

    protected void setEmail(String email) {
        this.assertArgumentNotEmpty(email, "邮件地址不能为空！");
        this.assertArgumentLength(email, 1, 100, "邮件地址长度不能超过100字！");
        this.assertArgumentTrue(
                Pattern.matches("\\w+([-+.']\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*", email),
                "Email address format is invalid.");
        this.email = email;
    }

    public String mobile() {
        return mobile;
    }

    protected void setMobile(String mobile) {
        this.assertArgumentNotEmpty(mobile, "手机号不能为空！");
        this.assertArgumentLength(mobile, 1, 20, "手机号长度不能超过{max}字！");
        this.mobile = mobile;
    }

    public Set<SysRoleEntity> roleEntities() {
        return roleEntities;
    }

    protected void setRoleEntities(Set<SysRoleEntity> roleEntities) {
        this.roleEntities = roleEntities;
    }

    public void login(String password) {
        this.assertUserActivate();
        this.assertArgumentEquals(this.password(), this.asEncryptedValue(password), "密码输入不正确！");
    }

    /**
     * 修改密码
     * @param newPwd
     */
    public void changePassword(String newPwd) {
        this.assertArgumentNotEmpty(newPwd, "新密码不能为空！");
        this.assertChangePasswordNotSame(newPwd);
        this.assertUsernamePasswordNotSame(newPwd);
        this.setPassword(DomainRegistry.encryptionService().encryptedValue(newPwd));
    }

    protected String asEncryptedValue(String aPlainTextPassword) {
        String encryptedValue = DomainRegistry.encryptionService()
                        .encryptedValue(aPlainTextPassword);
        return encryptedValue;
    }

    /**
     * 修改密码时，验证新密码与原始密码是否相同
     * @param newPwd
     */
    protected void assertChangePasswordNotSame(String newPwd){
        this.assertArgumentNotEquals(this.password(), this.asEncryptedValue(newPwd), "新密码与原始密码相同！");
    }


    /**
     * 验证输入密码时，两次输入的密码是否相同
     * @param password
     * @param confirmPassword
     */
    public void assertPasswordsSame(String password, String confirmPassword){
        this.assertArgumentEquals(password, confirmPassword, "两次输入的密码不相同！");
    }

    /**
     * 验证用户名是否与密码相同
     * @param password
     */
    protected void assertUsernamePasswordNotSame(String password) {
        this.assertArgumentNotEquals(this.username(), password, "用户名和密码不能相同！");
    }

    /**
     * 验证用户是否被禁用
     */
    public void assertUserActivate() {
        this.assertArgumentEquals(this.status().toString(), 1+"", "用户已禁用！");
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        SysUserEntity that = (SysUserEntity) o;
        return userId == that.userId &&
                Objects.equals(username, that.username) &&
                Objects.equals(name, that.name) &&
                Objects.equals(password, that.password) &&
                Objects.equals(email, that.email) &&
                Objects.equals(mobile, that.mobile) &&
                Objects.equals(this.status(), that.status()) &&
                Objects.equals(this.createUserId(), that.createUserId()) &&
                Objects.equals(this.createTime(), that.createTime());
    }

    @Override
    public int hashCode() {

        return Objects.hash(userId, username, name, password, email, mobile, status(), createUserId(), createTime());
    }
}
